/*
 * Copyright 2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.benmei.ntlive.vo;

import com.benmei.ntlive.constant.Constants;
import com.benmei.ntlive.dto.HandsUpListResponse;
import com.benmei.ntlive.dto.StudentSizeResponse;
import com.benmei.ntlive.entity.ClassRoomAction;
import com.benmei.ntlive.entity.ClassRoomEntryLog;
import com.benmei.ntlive.entity.MemberCourse;
import com.benmei.ntlive.exception.NtClientException;
import com.benmei.ntlive.service.LiveService;
import com.benmei.ntlive.utils.JsonUtil;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Channel Repository using HashMap
 *
 * @author Jibeom Jung
 */
public class SessionRepository {
    private static Logger logger = LoggerFactory.getLogger(SessionRepository.class);
    @Autowired
    private LiveService liveService;

    // key:"{courseType}_{roomId}_",value:Room
    private Map<String, Room> roomMap = new ConcurrentHashMap<String, Room>();

    // key:"{courseType}_{roomId}_",value:Room
    // 添加一个教室
    public Room createRoom(String courseType, Integer roomId) {
        Room room = new Room(roomId, courseType);
        roomMap.put(courseType + "_" + roomId, room);
        logger.info("Created roomSession,Current room size is {}", this.size());
        return room;
    }

    // 向教室里面的所有人发送举手队列
    public void sendHuandsUpListMessageForRoom(final Room room) {
        HandsUpListResponse response = new HandsUpListResponse(room);
        final String msg = JsonUtil.toJson(response);

        //向老师发送举手列表
        Iterator<Session> iteratorTea = room.getTeachers().iterator();
        while (iteratorTea.hasNext()) {
            Session teacher = iteratorTea.next();
            teacher.getChannel().writeAndFlush(msg + Constants.delimiter).addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess()) {
                        logger.info("举手发送给老师成功");

                    } else {
                        logger.error("举手发送给老师失败");
                    }
                }
            });
        }

        // 向学生发送举手列表
        Iterator<Session> iteratorStu = room.getStudents().iterator();
        while (iteratorStu.hasNext()) {
            Session student = iteratorStu.next();
            student.getChannel().writeAndFlush(msg + Constants.delimiter).addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess()) {
                        logger.info("举手发送给学生成功");
                    }else{
                        logger.info("举手发送给学生失败");
                    }
                }
            });
        }

    }

    // 向教室里面的所有人发送当前教室人数
    public void sendStudentSizeMessageForRoom(Room room) {
        Iterator<Session> iteratorStu = room.getStudents().iterator();
        StudentSizeResponse response = new StudentSizeResponse(room.getStudents().size());
        String msg = JsonUtil.toJson(response);
        // 向学生发送当前教室人数
        while (iteratorStu.hasNext()) {
            Session student = iteratorStu.next();
            student.getChannel().writeAndFlush(msg + Constants.delimiter);
        }

        // 向老师发送当前教室人数
        Iterator<Session> iteratorTea = room.getTeachers().iterator();
        while (iteratorTea.hasNext()) {
            Session teacher = iteratorTea.next();
            teacher.getChannel().writeAndFlush(msg + Constants.delimiter);
        }
    }

    // 获取一个教室
    public Room getRoom(String courseType, Integer roomId) {
        return roomMap.get(courseType + "_" + roomId);
    }

    // 根据endPoint（客户端ip和端口号）移除session
    public synchronized void remove(String endPoint) {
        Set<String> keys = roomMap.keySet();
        Iterator<String> keyIter = keys.iterator();

        int hasUserCount = 0;// 连接仓库中匹配到的用户的数量
        while (keyIter.hasNext()) {
            String key = keyIter.next();
            Room room = roomMap.get(key);
            // 如果endPoint是学生，则移除学生
            Session student = room.getStudentByEndpoint(endPoint);
            if (student != null) {
                hasUserCount++;
                // 记录日志
                ClassRoomEntryLog roomLog = new ClassRoomEntryLog();
                roomLog.setRoom_id(room.getRoomId());
                roomLog.setEvent_type("closeTcpSession");
                roomLog.setEvent_date(new Date());
                roomLog.setUser_id(student.getUser().getId());
                roomLog.setUser_role(Constants.UserRole.STUDENT);
                roomLog.setClient_os_type(student.getUser().getClientOsType());
                roomLog.setDetail("Closed TCP user session,endPoint:" + endPoint);
                roomLog.setCourse_type(room.getCourseTypeCode());
                liveService.roomLog(roomLog);

                room.removeStudent(student);// 学生队列中移除学生
                sendHuandsUpListMessageForRoom(room);// 如果有学生离开教室,向其他人发送举手队列
                sendStudentSizeMessageForRoom(room);// 发送当前教室学生数
            } else {
                Session teacher = room.getTeacherByEndpoint(endPoint);
                if (teacher != null) {
                    hasUserCount++;
                    ClassRoomEntryLog roomLog = new ClassRoomEntryLog();
                    roomLog.setRoom_id(room.getRoomId());
                    roomLog.setEvent_type("closeTcpSession");
                    roomLog.setEvent_date(new Date());
                    roomLog.setUser_id(teacher.getUser().getId());
                    roomLog.setUser_role(Constants.UserRole.TEACHER);
                    roomLog.setClient_os_type(teacher.getUser().getClientOsType());
                    roomLog.setCourse_type(room.getCourseTypeCode());
                    roomLog.setDetail("ClosedTCP user session,endPoint:" + endPoint);
                    liveService.roomLog(roomLog);
                    boolean result = room.getTeachers().remove(teacher);
                    logger.info("移除老师[{}]:[{}][{}]", result, teacher.getUser().getId(), teacher.getChannel().remoteAddress().toString());
                }
            }

            logger.info("移除用户后教室【{}】，学生数【{}】，老师数【{}】", room.getRoomType() + "_" + room.getRoomId(), room.getStudents().size(), room.getTeachers().size());
            // 如果教室是空的(老师和学生都不在教室)就移除教室，(最后一个人离开教室)
            if (room.isEmpty()) {
                ClassRoomEntryLog roomLog = new ClassRoomEntryLog();
                roomLog.setRoom_id(room.getRoomId());
                roomLog.setEvent_type("closeTcpRoomSession");
                roomLog.setEvent_date(new Date());
                roomLog.setDetail("关闭 TCP Room session,roomId:" + room.getRoomId());
                roomLog.setCourse_type(room.getCourseTypeCode());
                liveService.roomLog(roomLog);
                roomMap.remove(key);
            }
        }
        if (hasUserCount == 0) {
            logger.warn("从session仓库中移除session：仓库中不存在这个session（endPoint:" + endPoint + "）");
        }
    }

    // 根据endPoint获取用户（学生或老师），该方法会遍历所有教室中的所有老师和学生（效率慢，尽量不用）
    public Session getSessionByKey(String endPoint) {
        Set<String> keys = roomMap.keySet();
        Iterator<String> keyIter = keys.iterator();
        Session session = null;
        // 遍历所有教室
        while (keyIter.hasNext()) {
            String key = keyIter.next();
            Room room = roomMap.get(key);
            Iterator<Session> iteratorStu = room.getStudents().iterator();

            // 遍历教室里面的所有人（学生和老师）
            while (iteratorStu.hasNext()) {
                Session student = iteratorStu.next();
                if (student.getChannel().remoteAddress().toString().equals(endPoint)) {
                    session = student;
                    break;
                }
            }
            Iterator<Session> iteratorTea = room.getTeachers().iterator();
            while (iteratorTea.hasNext()) {
                Session teacher = iteratorTea.next();
                if (teacher.getChannel().remoteAddress().toString().equals(endPoint)) {
                    session = teacher;
                    break;
                }
            }
        }
        return session;
    }

    // 房间数量
    public int size() {
        return this.roomMap.size();
    }
}
